package gui;

import java.util.ArrayList;

import protocol.generic.AbstractProtocolManager;
import protocol.generic.Group;
import protocol.generic.ProtocolEventHandler;
import protocol.domain.GroupEntry;
import protocol.domain.Status;
import protocol.generic.ProtocolException;

import Delegate.GroupEntryDelegate;
import EventHandler.JambiEventHandler;
import EventHandler.YaimEventHandler;

import com.trolltech.qt.core.*;
import com.trolltech.qt.gui.QApplication;
import com.trolltech.qt.gui.QCloseEvent;
import com.trolltech.qt.gui.QDialog;
import com.trolltech.qt.gui.QFileDialog;
import com.trolltech.qt.gui.QIcon;
import com.trolltech.qt.gui.QMainWindow;
import com.trolltech.qt.gui.QMenu;
import com.trolltech.qt.gui.QMessageBox;
import com.trolltech.qt.gui.QPixmap;
import com.trolltech.qt.gui.QStyleFactory;
import com.trolltech.qt.gui.QFileDialog.Filter;
import com.trolltech.qt.gui.QAbstractItemView;

public class MainWindow extends QMainWindow {

	Ui_MainWindowClass ui= new Ui_MainWindowClass();
	ArrayList<AbstractProtocolManager> protocolManagers;
	ArrayList<Thread> threads;
	BuddyList buddyList;
	AccountManager am;

	public static void main(String[] args) throws Exception {
		QApplication.initialize(args);
		QApplication.setStyle(QStyleFactory.create("cleanlooks"));
		MainWindow mainWindow = new MainWindow();
		mainWindow.show();
		System.out.println("main : " + Thread.currentThread());
		QApplication.exec();
	}

	public MainWindow() {
		ui.setupUi(this);
		//set the presence combo box
		ui.presenceBox.setIconSize(new QSize(16,16));
		ui.presenceBox.addItem(new QIcon(new QPixmap("classpath:resources/available_22.png")), "Available");
		ui.presenceBox.addItem(new QIcon(new QPixmap("classpath:resources/away_22.png")), "Away");
		ui.presenceBox.addItem(new QIcon(new QPixmap("classpath:resources/extended-away_22.png")), "Extended away");
		ui.presenceBox.addItem(new QIcon(new QPixmap("classpath:resources/busy_22.png")), "Busy");
		ui.presenceBox.addItem(new QIcon(new QPixmap("classpath:resources/invisible_22.png")), "Chat");
		ui.presenceBox.addItem(new QIcon(new QPixmap("classpath:resources/offline_22.png")), "Unavailable");
		ui.presenceBox.activated.connect(this,"presenceSetted(String)");
		ui.presenceBox.setIconSize(new QSize(32,32));
		
		//set icon button
		QIcon icon=new QIcon(new QPixmap("classpath:resources/available.png"));
        ui.iconButton.setIcon(icon);
        ui.iconButton.setIconSize(new QSize(48,48));
        
        ui.treeView.header().hide();
        ui.treeView.setRootIsDecorated(false);
		ui.treeView.doubleClicked.connect(this,"openChatWindow(QModelIndex)");
		ui.treeView.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu);
		ui.treeView.customContextMenuRequested.connect(this, "Popmenu(QPoint)");
		ui.treeView.setDragEnabled(true);
		ui.treeView.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection);
		ui.treeView.viewport().setAcceptDrops(true);
		ui.treeView.setDropIndicatorShown(true);
		ui.treeView.setDragDropMode(QAbstractItemView.DragDropMode.InternalMove);
		
		ui.actionAccountManager.triggered.connect(this, "accountManagement()");
		ui.actionAddUser.triggered.connect(this, "addEntry()");
		ui.actionAddGroup.triggered.connect(this,"addGroup()");
		ui.actionAddGroup_2.triggered.connect(this, "addGroup()");
		ui.actionDelete.triggered.connect(this, "delete()");
		ui.actionRename.triggered.connect(this, "rename()");
		ui.actionBlock.triggered.connect(this, "block()");
		ui.actionUnblock.triggered.connect(this, "unblock()");
		ui.iconButton.clicked.connect(this,"changeIcon()");
		
		protocolManagers = new ArrayList<AbstractProtocolManager>();
		threads=new ArrayList<Thread>();
		buddyList = new BuddyList(this);
	}
	
	@Override
	public void closeEvent(QCloseEvent event) {
		try{
			this.disconnectAll();
			for(AbstractProtocolManager manager : this.protocolManagers)
				manager.close();
////			for(Thread thread : threads)
////				thread.stop();
////			this.threads.clear();
			this.protocolManagers.clear();
			
			for(QObject object : this.children()){
				if(object instanceof QDialog || object instanceof QMainWindow || object instanceof QMessageBox)
					object.dispose();
			}
			super.closeEvent(event);
		}
		catch(Exception e){
			
		}
		
	}
	
	
	
	
	/****************	AccountManager action's handler	************************
	 * to show a accountManager dialog.
	 ***************************************************************************/
	public void accountManagement(){
		am=new AccountManager(this);
	}
	
	/*****************************************************************************
	 * Every time an account is set on in the accountManager dialog,
	 * the account is getted from the protocolManagers list and is logined here.
	 *****************************************************************************/
	public void login() throws Exception {
		AbstractProtocolManager manager=this.protocolManagers.get(this.protocolManagers.size()-1);
		this.setEventListener(manager);
		if(manager.getProtocol().equalsIgnoreCase("yaim")){
			manager.connect();
			manager.login();
		}else{
			new Thread(manager).start();
//			manager.run();
		}
		
////		Thread temp=new Thread(manager);
////		temp.start();
////		threads.add(temp);
	}
	
	/***********************************************************************************
	 * These two methods below, set the "updatePresence" and "processIncomingMessage"
	 * for every protocol in the protocolManagers list
	 ************************************************************************************/
	private void setAllEventListeners() {
		for (int i = 0; i < protocolManagers.size(); i++) {
			setEventListener(protocolManagers.get(i));
		}
	}
	
	private void disconnectAll(){
		for (AbstractProtocolManager manager : protocolManagers){
			if(manager.getProtocol().equalsIgnoreCase("yaim")){
				YaimEventHandler handler = (YaimEventHandler) manager.getEventHandler();
				handler.entriesAdded.disconnect();
				handler.loggedIn.disconnect();
				handler.messageArrived.disconnect();
				handler.presenceChanged.disconnect();
				handler.authenticationPending.disconnect();
			}
			else{
				JambiEventHandler handler = (JambiEventHandler) manager.getEventHandler();
				handler.entriesAdded.disconnect();
				handler.loggedIn.disconnect();
				handler.messageArrived.disconnect();
				handler.presenceChanged.disconnect();
				handler.authenticationPending.disconnect();
			}
		}
	}

	private void setEventListener(AbstractProtocolManager manager) {
		if(manager.getProtocol().equalsIgnoreCase("yaim")){
			YaimEventHandler handler=(YaimEventHandler)manager.getEventHandler();
			handler.loggedIn.connect(this, "setBuddyList()");
			handler.entriesAdded.connect(this, "updateBuddyList()");
			handler.getPresenceChangedSignal().connect(buddyList,"updatePresence(UserPresence)");
			handler.getMessageArrivedSignal().connect(buddyList,"processIncomingMessage(InstantMessage)");
			handler.authenticationPending.connect(this, "Authenticate(String,AbstractProtocolManager)");
		}
		else{
			JambiEventHandler handler = (JambiEventHandler) manager.getEventHandler();
			handler.loggedIn.connect(this, "setBuddyList()");
			handler.entriesAdded.connect(this, "updateBuddyList()");
			handler.getPresenceChangedSignal().connect(buddyList,"updatePresence(UserPresence)");
			handler.getMessageArrivedSignal().connect(buddyList,"processIncomingMessage(InstantMessage)");
			handler.authenticationPending.connect(this, "Authenticate(String,AbstractProtocolManager)");
		}
		System.out.println("setting finished");
	}

	/*******************************************************************************************
	 * Every time this method is called, it only add the latest added protocol's GroupList
	 * into the buddylist view.
	 *******************************************************************************************/
	public void setBuddyList() {
		
		System.out.println("buddy"); 
		//only add the latest added protocol
		AbstractProtocolManager manager=protocolManagers.get(protocolManagers.size()-1);
		buddyList.addGroupList(protocolManagers.get(protocolManagers.size()-1), protocolManagers.get(protocolManagers.size()-1).getGroups());
		
		GroupEntryDelegate geDelegate=new GroupEntryDelegate();
        geDelegate.setBuddyList(buddyList);
        ui.treeView.setItemDelegate(geDelegate);
		ui.treeView.setModel(buddyList);
		ui.treeView.expandAll();
		ui.treeView.setIconSize(new QSize(32, 32));
		
		QPixmap pixmap=new QPixmap();
		try {
			pixmap.loadFromData(manager.getAvatar(manager.getUserID()));
		} catch (Exception e) {
			return;
		}
		this.ui.iconButton.setIcon(new QIcon(pixmap));
		/**/
	}
	
	/***************************************************************************
	 * Every time this method is called, the buddylist will be updated. It means
	 * that every protocol's grouplist is reloaded again.
	 ***************************************************************************/
	public void updateBuddyList(){
		
		disconnectAll();
		buddyList = new BuddyList(this);
//		buddyList.clear();
		setAllEventListeners();
		
		for (int i = 0; i < protocolManagers.size(); i++) {
			buddyList.addGroupList(protocolManagers.get(i), protocolManagers
					.get(i).getGroups());
		}
		
		GroupEntryDelegate geDelegate=new GroupEntryDelegate();
        geDelegate.setBuddyList(buddyList);
        ui.treeView.setItemDelegate(geDelegate);
		ui.treeView.setModel(buddyList);
		ui.treeView.expandAll();
		ui.treeView.setIconSize(new QSize(32, 32));
	}

	/******************	treeView.doubleClicked's handler	*****************************
	 * If one item in the buddylist is double clicked, a new chat window to this buddy
	 * is showed.
	 ************************************************************************************/
	public void openChatWindow(QModelIndex index) {
		System.out.println(index.row());
		BuddyList buddyList = (BuddyList) ui.treeView.model();
		Object node = buddyList.indexToValue(index);

		if (node instanceof GroupEntry) {
			GroupEntry entry = (GroupEntry) node;
			buddyList.openChatWindow(entry);
			System.out.println(entry);
		}
	}
	
	/***************************	iconButton's handler	*****************************
	 * To change the user's avatar
	 * 
	 * Every time the iconButton button is clicked, this method is called, and it will
	 * open a file dialog to let user change the avatar.
	 ************************************************************************************/
	public void changeIcon(){
		String fileName = QFileDialog.getOpenFileName(this,"Open Image", "/home/",new Filter("Image Files (*.png *.jpg *.bmp)"));
        if (fileName.length() == 0)
            return;

        for(AbstractProtocolManager ma : this.protocolManagers){
        	try {
				ma.setAvatar(fileName);
			} catch (ProtocolException e) {
				e.printStackTrace();
				QMessageBox.critical(this, "Error", "Avatar change failed!");
			}
        }
        QIcon icon=new QIcon(new QPixmap(fileName));
        ui.iconButton.setIcon(icon);
        ui.iconButton.setIconSize(new QSize(48,48));
	}
	
	public void presenceSetted(String presence){
		System.out.println(presence);
		Status myStatus;
		if(presence.equalsIgnoreCase(Status.AVAILABLE.toString()))
			myStatus=Status.AVAILABLE;
		else if(presence.equalsIgnoreCase(Status.AWAY.toString()))
			myStatus=Status.AWAY;
		else if(presence.equalsIgnoreCase(Status.BUSY.toString()))
			myStatus=Status.BUSY;
		else if(presence.equalsIgnoreCase(Status.CHAT.toString()))
			myStatus=Status.CHAT;
		else if(presence.equalsIgnoreCase(Status.EXTENDED_AWAY.toString()))
			myStatus=Status.EXTENDED_AWAY;
		else
			myStatus=Status.UNAVAILABLE;
		
		for(AbstractProtocolManager pm : protocolManagers){
			pm.setPresence(myStatus);
		}
	}
	
	public void Authenticate(String clientID,AbstractProtocolManager manager){
		Authenticate auth=new Authenticate(this,clientID,manager);
	}

	public void addGroup(){
		AddGroup ag=new AddGroup(this);
	}
	
	public void rename(){
		QModelIndex index=ui.treeView.currentIndex();
		String s=(String)index.data(0);
		Rename rename=new Rename(this,s);
	}
	
	public void block(){
		QModelIndex index=ui.treeView.currentIndex();
		String s=(String)index.data(0);
		String ss[]=s.split("#");
		GroupEntry entry=this.buddyList.getGroupEntryByID(ss[3]);
		this.buddyList.getManagerByEntry(entry).block(ss[3]);
	}
	public void unblock(){
		QModelIndex index=ui.treeView.currentIndex();
		String s=(String)index.data(0);
		String ss[]=s.split("#");
		GroupEntry entry=this.buddyList.getGroupEntryByID(ss[3]);
		this.buddyList.getManagerByEntry(entry).cancelBlock(ss[3]);
	}
	
	public void addEntry(){
		AddEntry ae=new AddEntry(this);
	}
	
	public void delete() {
		QModelIndex index=ui.treeView.currentIndex();
		String s=(String)index.data(0);
		String ss[]=s.split("#");
		System.out.println(s);
		
		if(ss.length!=1){
			for(AbstractProtocolManager apm : protocolManagers){
				try {
					System.out.println((String)index.parent().data()+"********"+ss[3]);
					if(apm.getProtocol().equalsIgnoreCase("yaim")){
						apm.deleteEntry(ss[3]);
					}
					else{
						apm.deleteEntryFromGroup((String)index.parent().data(), ss[3]);
						this.updateBuddyList();
					}
				} catch (ProtocolException e) {
					// TODO Auto-generated catch block
				}
			}
		}
		else{
			for(AbstractProtocolManager apm : protocolManagers){
				try {
					System.out.println(s);
					apm.deleteGroup(s);
					this.updateBuddyList();
				} catch (ProtocolException e) {
					// TODO Auto-generated catch block
				}
			}
		}
	}
	
	public void Popmenu(QPoint point){
		QMenu menu = this.createPopupMenu();
		menu.removeAction(menu.actions().get(0));
		
		QModelIndex index=ui.treeView.currentIndex();
		String s=(String)index.data(0);
		String ss[]=s.split("#");
		if(ss.length==1){
			menu.addAction(ui.actionAddGroup_2);
			menu.addAction(ui.actionAddUser);
			menu.addAction(ui.actionDelete);
			menu.addAction(ui.actionRename);
		}
		else{
			if(ss[4].equalsIgnoreCase("true")){
				menu.addAction(ui.actionAddGroup_2);
				menu.addAction(ui.actionAddUser);
				menu.addAction(ui.actionDelete);
				menu.addAction(ui.actionRename);
				menu.addAction(ui.actionUnblock);
			}
			else{
				menu.addAction(ui.actionAddGroup_2);
				menu.addAction(ui.actionAddUser);
				menu.addAction(ui.actionDelete);
				menu.addAction(ui.actionRename);
				menu.addAction(ui.actionBlock);
			}
		}
		
		menu.exec(ui.treeView.mapToGlobal(point));
	}

}

